use std::fmt::Error;
use std::io;
use std::ops::Add;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use crate::bound::SidecarInBoundPort;
use crate::codes::http::Request;
use crate::{JaegerTracing, Response};

pub struct AsyncInboundServer{
    listener:TcpListener,
    local_stream:TcpStream,
    trace:Option<JaegerTracing>,
}

impl AsyncInboundServer {
    pub async fn new(port:i32,trace:Option<JaegerTracing>) -> Self {
        let mut addr = String::from("0.0.0.0");
        addr.push(':');
        addr = addr.add(SidecarInBoundPort.to_string().as_str());

        let listener = TcpListener::bind(addr).await.unwrap();

        let mut local = String::from("127.0.0.1:");
        local = local.add(port.to_string().as_str());
        let conn = TcpStream::connect(local).await.unwrap();

        AsyncInboundServer{
            listener,
            local_stream: conn,
            trace
        }
    }

    pub async fn run(mut self) -> Result<(),io::Error> {
        loop {
            let (mut stream,_) = self.listener.accept().await?;
            let opt = self.trace.clone();
            match opt {
                None => {
                    let mut buf = [0;1024];
                    let size = stream.read(&mut buf).await?;
                    if size == 0 {
                        continue;
                    }

                    let mut data = buf[..size].to_vec();
                    let mut rs = Request::read_from_data(data.clone());
                    if let None = rs {
                        continue;
                    }
                    let request = rs.unwrap();

                    let new_request = request.into_bytes();
                    let local_res = self.local_stream.write(new_request.as_slice()).await?;

                    let mut buf = [0;1024];
                    let size = self.local_stream.read(&mut buf).await?;

                    let res_data = buf[..size].to_vec();
                    let r = Response::from_tcp_data(res_data);
                    if let None = r {
                        continue;
                    }

                    let response = r.unwrap();
                    let op = stream.write(response.into_bytes().as_slice()).await?;

                },
                Some(trace) => {

                }
            }
        }

    }
}